import { Scene } from "@babylonjs/core/scene";
import { CanvasTextureGradient } from '../texture/canvas-texture-gradient';
import { Mesh } from "@babylonjs/core/Meshes/mesh";
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder";
import { StandardMaterial } from "@babylonjs/core/Materials/standardMaterial";
import { Texture } from "@babylonjs/core/Materials/Textures/texture";
import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
import { Vector3 } from "@babylonjs/core/Maths/math.vector";


/**
 * 天空球参数对象
 * @param billboardMode 朝向模式
 * @param values 上下区域值集合
 * @param colors 区域值对应的颜色集合
 * @param size 大小
 * @param segments 分段数
 * @param rotation 旋转
 * @param canvasWidth 画布像素宽
 * @param canvasHeight 画布像素高
 */
interface IGradientSkyBox {
    billboardMode?: number,
    values?: number[],
    colors?: string[],
    size?: number,
    segments?: number,
    rotation?: Vector3,
    canvasWidth?: number,
    canvasHeight?: number,
}


/**
 * 天空球
 * @param name 名称
 * @param scene 所在场景
 * @param options 参数对象
 */
class GradientSkybox {

    private _option: IGradientSkyBox;
    private _name: string;
    private _scene: Scene;

    public readonly mesh: Mesh;

    constructor(name: string, scene: Scene, options?: IGradientSkyBox) {
        this._name = name;
        this._scene = scene;
        this._option = options || {};
        const container = new TransformNode(name + '-container', scene);
        this.mesh = this.createMesh(name, scene, this._option);
        this.mesh.rotation = this._option.rotation || new Vector3(0, 0, 0);
        this.mesh.parent = container;
        container.billboardMode = this._option.billboardMode || Mesh.BILLBOARDMODE_NONE;
        (this.mesh.material as StandardMaterial).emissiveTexture = this.drawTexture(name, scene, this._option);
    }

    public setGradient(values: number[], colors: string[]): void {
        this._option.values = values;
        this._option.colors = colors;
        (this.mesh.material as StandardMaterial).emissiveTexture = this.drawTexture(this._name, this._scene, this._option);
    }

    /**
     * 绘制纹理
     * @param name 名称 
     * @param scene 所在场景
     * @param options 参数对象
     * @returns 创建的纹理
     */
    private drawTexture(name: string, scene: Scene, options: IGradientSkyBox): Texture {
        const values = options.values;
        const colors = options.colors || [];
        let colorStops: any = [];
        if (values && values.length > 0) {
            if (values.length < 2) {
                colorStops.push(
                    {
                        value: 0,
                        color: colors[0] || '#9fddf4',
                    },
                    {
                        value: 1,
                        color: colors[0] || '#9fddf4',
                    }
                );
            } else {
                for (let i = 0; i < values.length; i++) {
                    colorStops.push({
                        value: values[i],
                        color: colors[i] || '#9fddf4',
                    });
                }
            }
        } else {
            colorStops = [
                {
                    value: 0,
                    color: '#9fddf4'
                },
                {
                    value: 0.3,
                    color: '#9fddf4'
                },
                {
                    value: 0.7,
                    color: '#082530'
                },
                {
                    value: 1,
                    color: '#082530'
                }
            ];
        }
        const skyTex = new CanvasTextureGradient(name + '-texture', {
            colorStops: colorStops,
            width: options.canvasWidth || 512,
            height: options.canvasHeight || 512
        }, scene);
        skyTex.texture.wrapU = 0;
        skyTex.texture.wrapV = 0;
        return skyTex.texture;
    }

    /**
     * 创建球形网格
     * @param name 名称
     * @param scene 所在场景
     * @param options 参数对象
     * @returns 网格
     */
    private createMesh(name: string, scene: Scene, options: IGradientSkyBox): Mesh {
        const sky = MeshBuilder.CreateSphere(name + '-mesh', { diameter: options.size || 100, segments: options.segments || 8, updatable: false }, scene);
        const skyMaterial = new StandardMaterial(name + '-material', scene);
        skyMaterial.disableLighting = true;
        skyMaterial.cullBackFaces = false;
        sky.material = skyMaterial;
        sky.isPickable = false;
        return sky;
    }

}


export { GradientSkybox };